#include <mezza/vstr.h>
#include <mezza/str.h>
#include <mezza/int.h>
#include <mezza/lang.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static mzvstr_t _mzvstr_alloc(mzsize_t vsize) {
    mzobj_t obj;

    if(NULL == (obj = (mzobj_t)malloc(sizeof(mzsize_t) + (vsize * sizeof(mzstr_t))))) return NULL;

    /* Coloca a informação de tamanho no objeto */
    OBJ_META(obj) = vsize;

    return (mzvstr_t)OBJ_SUB(obj);;
}

/*
	Aloca um vetor de strings

	13.11.2012
		Aprimorada a checagem de erros.EXPORTAR
	07.11.2013
		Modificado para refletir a intenção de exportação
		Correção dos relatórios de erros
		Comentários completados
		Compilação opcional para as checagens de parâmetros
	15.01.2015 (D. A)
		Exportada finalmente para a biblioteca mezza.
		Removida checagem de parâmetros tradicional
		Adicionada tolerância a parâmetros incorretos (mzsize_t=0).
		Uso de tipos novos e mais claros.
    01.02.2015 (D. A)
        Revisada para adotar métodos novos de tratamento de meta
        informação.
*/
mzvstr_t mzvstr_new(mzsize_t vsize, mzsize_t ssize)
{
	mzvstr_t ret;
	register mzsize_t i;

	if(vsize && ssize) {
		/* Aloca o vetor de strings */
		if(NULL == (ret = _mzvstr_alloc(vsize))) return NULL;

		/* Aloca cada string do vetor */
		i = vsize;
		ML_REPEAT_DOWN(i) /* percorrer de trás para frente */
		{
			if(NULL == (ret[i]=mzstr_new_bysize(ssize))) {
			/* Em caso de falha...
				...Desaloca cada string já alocada... */
				ML_REPEAT_TOEND(i, vsize) mzstr_free(ret[i]); /* percorrer em sentido normal */
				/* ...bem como o próprio vetor. */
				free(OBJ(ret));
				return NULL;
			}
		}
		return ret;
	}

    /* Se parâmetros incorretos, não faz nada além de retornar NULL */
	return NULL;
}

/*
	Desaloca um vetor de strings

	13.11.2012
		Criada
	07.11.2013
		Adicionada compilação opcional da checagen de parâmetros
	15.01.2015 (D. A)
		Exportada finalmente para a biblioteca mezza.
		Removida checagem de parâmetros tradicional
		Adicionada tolerância a parâmetros incorretos (mzsize_t=0).
		Uso de tipos novos e mais claros.
    01.02.2015 (D. A)
        Revisada para adotar métodos novos de tratamento de meta
        informação.

*/
mzvstr_t mzvstr_free(mzvstr_t vs)
{
	if(vs)
	{
		mzsize_t vsize;
		mzobj_t obj;

		obj = OBJ(vs);

		vsize = OBJ_META(obj);

		ML_REPEAT_DOWN(vsize) if(vs[vsize]) mzstr_free(vs[vsize]);

		free(obj);
	}

	return NULL;
}

int mzvstr_mov(mzvstr_t dest, mzvstr_t orig) {
    mzsize_t dest_sz;
    mzsize_t orig_sz;

    dest_sz = OBJ_META(OBJ(dest));
    orig_sz = OBJ_META(OBJ(orig));

    if(dest_sz > orig_sz) SWAP_INT(dest_sz, orig_sz);

    ML_REPEAT_DOWN(dest_sz) dest[dest_sz] = orig[dest_sz];

    return 0;
}

int mzvstr_cpy(mzvstr_t dest, mzvstr_t orig) {
    mzsize_t dest_sz;
    mzsize_t orig_sz;

    dest_sz = OBJ_META(OBJ(dest));
    orig_sz = OBJ_META(OBJ(orig));

    if(dest_sz > orig_sz) SWAP_INT(dest_sz, orig_sz);

    ML_REPEAT_DOWN(dest_sz) mzstr_cpy(dest[dest_sz], orig[dest_sz]);

    return 0;
}

/*
	Realoca um vetor de strings

	13.11.2012
		Aprimorada a checagem de erros
	07.11.2013
		Revisão do algorítmo e comentários
		Adição de compilação opcional para as checagens de parametros
	15.01.2015 (D. A)
		Exportada finalmente para a biblioteca mezza.
		Removida checagem de parâmetros tradicional
		Adicionada tolerância a parâmetros incorretos (mzsize_t=0).
		Uso de tipos novos e mais claros.
		Uso de mzvstr_new para evitar repetições.
    01.02.2015 (D. A)
        Revisada para adotar métodos novos de tratamento de meta
        informação.
*/
int mzvstr_realloc(mzvstr_t *vs, mzsize_t vsize, mzsize_t ssize)
{
	mzvstr_t newvs;
	mzsize_t ssize_idx;
	mzsize_t vsize_idx;

	/* Obtém o tamanho atual do vetor */
	vsize_idx	= OBJ_META(OBJ(*vs));

	if(vsize_idx != vsize) {
        /* Obtém o tamanho atual da string */
        ssize_idx   = OBJ_META(OBJ(*(*vs)));

        /* Checa se o tamanho da string mudou */
        if(ssize_idx != ssize) {
            /* Se mudou ... */

            /* Cria um novo vetor de strings completo */
            if(NULL == (newvs = mzvstr_new(vsize, ssize))) return -1;


            /* Copia o antigo vetor para o novo */
            mzvstr_cpy(newvs, *vs);

            /* Libera o vetor antigo */
            mzvstr_free(*vs);
        } else {
            /* Se NÃO mudou ... */
            mzsize_t vsize_idx_L;
            /* ALOCA, apenas, o vetor, sem alocar cada string*/
            if(NULL == (newvs = _mzvstr_alloc(vsize))) return -2;

            /* Checa se o tamanho do vetor diminuiu */
            if(vsize_idx > vsize) {
                /* Neste caso, libera a memória extra (strings) que o vetor antigo ocupava */
                vsize_idx_L = vsize;
                ML_REPEAT_TOEND(vsize_idx_L, vsize_idx) mzstr_free((*vs)[vsize_idx_L]);
            }

            /* Move as strings restantes para o novo vetor */
            mzvstr_mov(newvs, (*vs));

            /* Libera o objeto do vetor */
            FREE_OBJ(*vs);
        }

        /* Retorna o novo vetor na mesma variável */
        *vs = newvs;

        /* retorna sucesso */
        return 0;
	}
	return -3;
}
